package cn.simon.controller;


import cn.simon.exception.GlobalException;
import cn.simon.pojo.Order;
import cn.simon.pojo.SeckillMessage;
import cn.simon.pojo.SeckillOrder;
import cn.simon.pojo.User;
import cn.simon.rabbitmq.MQseckillSend;
import cn.simon.service.ISeckillOrderService;
import cn.simon.service.Impl.GoodsServiceImpl;
import cn.simon.service.Impl.OrderServiceImpl;
import cn.simon.service.Impl.SeckillOrderServiceImpl;
import cn.simon.util.JsonUtil;
import cn.simon.vo.GoodsVo;
import cn.simon.vo.OrderVo;
import cn.simon.vo.RespBean;
import cn.simon.vo.RespBeanEnum;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wf.captcha.ArithmeticCaptcha;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    @Autowired
    private GoodsServiceImpl goodsService;

    @Autowired
    private OrderServiceImpl orderService;

    @Autowired
    private ISeckillOrderService seckillOrderService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private MQseckillSend mQseckillSend;
    @Autowired
    private DefaultRedisScript redisScript;

    //内存标记位，减小redis的访问量
    private Map<String,Boolean> EmptyStackMap = new HashMap<>();

    @RequestMapping(value = "/{path}/doSeckill",method = RequestMethod.POST)
    @ResponseBody
    public RespBean doSeckill(@PathVariable String path, User user,Long goodsId){
        if(user == null){
            return RespBean.error(RespBeanEnum.SESSION_USER_NOEXCIT);
        }
        if(goodsId == null){
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        boolean cheak = orderService.checkPath(user,goodsId,path);
        if(!cheak){
            return RespBean.error(RespBeanEnum.PATH_NOTEXIST);
        }

        ValueOperations valueOperations = redisTemplate.opsForValue();

        //判断是否重新抢购
        SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("userId:" + user.getId() + ":" + goodsId);
        if(seckillOrder != null){
            return RespBean.error(RespBeanEnum.REPATER_SECKILL);
        }

        //内存标记，减少reids访问
        if (!EmptyStackMap.get("GoodsId:"+goodsId)){
            log.info("goodsId:___________"+goodsId);
            return RespBean.error(RespBeanEnum.STOCK_EMPETY);

        }

        log.info("goodsId:"+goodsId);
        //预减库存
//        Long stock = valueOperations.decrement("GoodsId:"+goodsId);
        //使用Lua脚本实现redis的分布式锁减少库存，保证操作的原子性
        //Redis会将整个脚本作为一个整体执行，中间不会被其他请求插入。因此在脚本运行过程中无需担心会出现竞态条件，无需使用事务
        Long stock = (Long) redisTemplate.execute(redisScript, Collections.singletonList("GoodsId:" + goodsId)
                , Collections.EMPTY_LIST);
        log.info("++++++++++stock:"+stock);
        if(stock < 0){
            EmptyStackMap.put("GoodsId"+goodsId,false);
            valueOperations.increment("GoodsId:"+goodsId);
            return RespBean.error(RespBeanEnum.STOCK_EMPETY);
        }

        SeckillMessage  message = new SeckillMessage(user,goodsId);
        //加入消息队列，（异步操作）
        mQseckillSend.sendSeckillMessage(JsonUtil.object2JsonStr(message));
        return RespBean.success(0);

       /* GoodsVo goods = (GoodsVo) goodsService.findGoodsVoById(goodsId);
        //判断库存
        if(goods.getStockCount() < 1){
            return RespBean.error(RespBeanEnum.STOCK_EMPETY);
        }
        //判断是否重复抢购
//        SeckillOrder seckillOrder = seckillOrderService.getOne(new QueryWrapper<SeckillOrder>()
//                .eq("user_id",user.getId())
//                .eq("goods_id",goodsId));
        SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("userId:" + user.getId() + ":" + goods.getId());
        if(seckillOrder != null){
            return RespBean.error(RespBeanEnum.REPATER_SECKILL);
        }
        log.info("用户——："+user+"上传商品"+goods);
        Order order = orderService.seckill(user,goods);
        orderVo.setGoods(goods);
        orderVo.setOrder(order);

        return RespBean.success(order);*/
    }

    /**
     * @功能描述: 获取秒杀结果
     * @Param:
     * @Return: orderId , -1 秒杀失败， 0 秒杀排队中， >0 秒杀成功返回订单号
     * @Author simon-yi'an
     * @Date 2022/11/7 14:04
     */
    @RequestMapping(value = "/result",method = RequestMethod.GET)
    @ResponseBody
    public RespBean getResult(User user,Long goodsId){
        if(user == null){
            return RespBean.error(RespBeanEnum.SESSION_USER_NOEXCIT);
        }
        Long orderId = seckillOrderService.getResult(user,goodsId);
        return RespBean.success(orderId);
    }

    @RequestMapping(value = "/seckillPath",method = RequestMethod.GET)
    @ResponseBody
    public RespBean doSeckillPath(User user,Long goodsId,String captcha){
        if (user == null){
            return RespBean.error(RespBeanEnum.SESSION_USER_NOEXCIT);
        }
        if (StringUtils.isEmpty(captcha)){
            return RespBean.error(RespBeanEnum.CAPTCHA_NOTEXIST);
        }
        //校验验证码
        boolean flag = orderService.checkCaptcha(user,goodsId,captcha);
        if (!flag){
            return RespBean.error(RespBeanEnum.CAPTCHA_ERROR);
        }
        String path = orderService.createPath(user,goodsId);

        return RespBean.success(path);
    }

    @GetMapping(value = "/captcha")
    public void verifyCode(User User, Long goodsId, HttpServletResponse response) {
        if (User == null || goodsId < 0) {
            throw new GlobalException(RespBeanEnum.SESSION_USER_NOEXCIT);
        }
        //设置请求头为输出图片的类型
        response.setContentType("image/jpg");
        response.setHeader("Pargam", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        //生成验证码
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
        redisTemplate.opsForValue().set("captcha:" + User.getId() + ":" + goodsId, captcha.text(), 300, TimeUnit.SECONDS);
        try {
            captcha.out(response.getOutputStream());
        } catch (IOException e) {
            log.error("验证码生成失败", e.getMessage());
        }
    }
/**
 * @功能描述: 初始化设置，再启动前在redis中加载好每个商品的库存量
 * @Param:
 * @Return:
 * @Author simon-yi'an
 * @Date 2022/11/7 13:59
 */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> list = goodsService.findGoodsVo();
        if (CollectionUtils.isEmpty(list)){
            return;
        }
        list.forEach(goods ->{
            if(goods.getStockCount() > 0){
                EmptyStackMap.put("GoodsId:"+goods.getId(),true);
                redisTemplate.opsForValue().set("GoodsId:"+goods.getId(),goods.getStockCount());
            }else{
                EmptyStackMap.put("GoodsId:"+goods.getId(),false);
                redisTemplate.opsForValue().set("GoodsId:"+goods.getId(),0);
            }

        });
    }
}
